﻿using SlamDunk.MES.Domain.Entities.ResourceContext;
using SlamDunk.MES.Domain.Entities.StockContext;
using SlamDunk.MES.Domain.IDomainServices;
using SlamDunk.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SlamDunk.MES.DomainService.Implements
{
    /// <summary>
    /// 物料条码领域服务接口
    /// </summary>
    public class MaterialBarcodeService : IMaterialBarcodeService
    {
        #region # 字段及构造器

        /// <summary>
        /// 编号领域服务接口
        /// </summary>
        private readonly INumberService _numberSvc;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public MaterialBarcodeService(INumberService numberSvc)
        {
            this._numberSvc = numberSvc;
        }

        #endregion

        #region # 生成物料条码 —— ICollection<MaterialBarcode> GenerateMaterialBarcodes(Material material...
        /// <summary>
        /// 生成物料条码
        /// </summary>
        /// <param name="material">物料定义</param>
        /// <param name="materialLot">物料批次</param>
        /// <param name="quantity">物料数量</param>
        /// <returns>物料条码</returns>
        public ICollection<MaterialBarcode> GenerateMaterialBarcodes(Material material, MaterialLot materialLot, decimal quantity)
        {
            #region # 验证

            if (material.MaterialBarcodeSetting == null)
            {
                throw new InvalidOperationException("物料定义未配置物料条码设置！");
            }
            if (material.MaterialBarcodeSetting.BarcodeMode != BarcodeMode.Unique)
            {
                throw new InvalidOperationException("物料定义未配置唯一码模式！");
            }

            #endregion

            Guid? facilityId = materialLot?.FacilityId ?? material.FacilityId;
            int materialBarcodeCount;               //条码数量
            decimal materialBarcodeQuantity;        //条码物料数量

            #region # 条码数量判断

            if (material.MaterialPack != null && material.MaterialBarcodeSetting.BarcodeUnit == material.MaterialPack.MaxPack)
            {
                materialBarcodeCount = (int)Math.Ceiling(quantity / (material.MaterialPack.MaxPackCoefficient.Value *
                                                                     material.MaterialPack.MinPackCoefficient));
                materialBarcodeQuantity = (material.MaterialPack.MaxPackCoefficient.Value * material.MaterialPack.MinPackCoefficient);
            }
            else if (material.MaterialPack != null && material.MaterialBarcodeSetting.BarcodeUnit == material.MaterialPack.MinPack)
            {
                materialBarcodeCount = (int)Math.Ceiling(quantity / material.MaterialPack.MinPackCoefficient);
                materialBarcodeQuantity = material.MaterialPack.MinPackCoefficient;
            }
            else
            {
                materialBarcodeCount = (int)Math.Ceiling(quantity);
                materialBarcodeQuantity = quantity;
            }

            #endregion

            string[] materialBarcodeNos = this._numberSvc.GenerateMaterialBarcodeNos(materialBarcodeCount);
            IEnumerable<MaterialBarcode> materialBarcodes =
                from materialBarcodeNo in materialBarcodeNos
                select new MaterialBarcode(materialBarcodeNo, material.Id, materialLot?.Id, facilityId, materialBarcodeQuantity);

            return materialBarcodes.ToList();
        }
        #endregion
    }
}
